package register

import (
	"context"
	"fmt"
	"time"

	"chat.com/server/grpc/grpcclient"
	"chat.com/setting"
	"github.com/samuel/go-zookeeper/zk"
)

func Init() {
	ServerRegisterInstance = NewServerRegister()
	// 创建注册中心
	ServerRegisterInstance.CreateCenter(setting.ZookeeperSetting.AccServerCenter)
	ServerRegisterInstance.CreateCenter(setting.ZookeeperSetting.RpcServerCenter)

	// 监听注册中心
	//go ServerRegisterInstance.Watch(setting.ZookeeperSetting.AccServerCenter)
	go ServerRegisterInstance.Watch(setting.ZookeeperSetting.RpcServerCenter)
}

/**************************** ServerRegister *******************************/
var ServerRegisterInstance *ServerRegister

type ServerRegister struct {
	conn *zk.Conn
}

func NewServerRegister() *ServerRegister {
	conn, _, err := zk.Connect([]string{setting.ZookeeperSetting.Host}, 5*time.Second)
	if err != nil {
		fmt.Println(err)
		panic(err)
	}

	s := ServerRegister{conn: conn}
	return &s
}

// 创建acc-server注册中心
func (s *ServerRegister) CreateCenter(serverCenterName string) error {

	var data = []byte(fmt.Sprintf("%s servers center", serverCenterName))
	var flags int32 = 0

	// 获取访问控制权限
	acls := zk.WorldACL(zk.PermAll)
	path := fmt.Sprintf("/%s", serverCenterName)
	res, err := s.conn.Create(path, data, flags, acls)

	if err != nil {
		fmt.Printf("创建注册中心失败: %v\n", err)
		return err
	}

	fmt.Printf("创建: %s 成功\n", res)
	return nil
}

// 注册acc-server节点
func (s *ServerRegister) RegisterNode(serverCenterName, serverName, serverAddr string) error {

	var data = []byte(serverAddr)
	var flags int32 = 0

	// 获取访问控制权限
	acls := zk.WorldACL(zk.PermAll)
	path := fmt.Sprintf("/%s/%s", serverCenterName, serverName)
	res, err := s.conn.Create(path, data, flags, acls)

	if err != nil {
		fmt.Printf("注册节点失败: %v\n", err)
		return err
	}

	fmt.Printf("注册节点: %s 成功\n", res)

	return nil
}

// 修改acc-server节点信息
func (s *ServerRegister) ModifyNode(serverCenterName, serverName, serverAddr string) error {

	path := fmt.Sprintf("/%s/%s", serverCenterName, serverName)
	newData := []byte(serverAddr)

	_, sate, _ := s.conn.Get(path)
	_, err := s.conn.Set(path, newData, sate.Version)

	if err != nil {
		fmt.Printf("修改节点信息失败: %v\n", err)
		return err
	}

	fmt.Println("修改节点信息成功")

	return nil
}

// 注销acc-server节点信息，但不删除节点
func (s *ServerRegister) WriteOffNode(serverCenterName, serverName string) error {

	path := fmt.Sprintf("/%s/%s", serverCenterName, serverName)
	// 注销地址信息
	newData := []byte("")

	_, sate, _ := s.conn.Get(path)
	_, err := s.conn.Set(path, newData, sate.Version)

	if err != nil {
		fmt.Printf("注销节点信息失败: %v\n", err)
		return err
	}

	fmt.Println("注销节点信息成功")

	return nil
}

// 删除acc-server节点
func (s *ServerRegister) DelNode(serverCenterName, serverName string) error {

	path := fmt.Sprintf("/%s/%s", serverCenterName, serverName)

	_, sate, _ := s.conn.Get(path)
	err := s.conn.Delete(path, sate.Version)

	if err != nil {
		fmt.Printf("节点删除失败: %v\n", err)
		return err
	}

	fmt.Println("节点删除成功")

	return nil
}

// 返回所有acc-servers下属的节点
func (s *ServerRegister) GetAllNodes(serverCenterName string) ([]string, error) {

	path := serverCenterName
	nodes, _, err := s.conn.Children(path)
	return nodes, err

	/*
		addrs := []string{}

		for _, node := range nodes {
			addrByte, _, _ := s.conn.Get(fmt.Sprintf("/%s/%s", path, node))
			if err != nil {
				fmt.Printf("查询%s失败, err: %v\n", path, err)
				return nil, err
			}

			addrs = append(addrs, string(addrByte))
		}

		fmt.Printf("%s 的所有server为 %s\n", path, nodes)
		fmt.Printf("%s 的所有server ip为 %s\n", path, addrs)

		return addrs, nil*/
}

// 监听注册中心下属的节点数量变化
func (s *ServerRegister) Watch(serverCenterName string) {

	for {

		ctx, cancelFunc := context.WithCancel(context.Background())

		path := fmt.Sprintf("/%s", serverCenterName)
		nodes, _, _ := s.conn.Children(path)
		for _, node := range nodes {

			// 不监听自己，不用建立grpc client
			if node == setting.RpcServerSetting.Name {
				continue
			}

			nodePath := fmt.Sprintf("%s/%s", path, node)
			go s.watchNode(ctx, nodePath, node)
		}

		// 监听 serverCenterName 的数据
		_, _, event, err := s.conn.ChildrenW(path)
		if err != nil {
			panic(err)
		}

		<-event

		/*fmt.Println("Watch发生回调:")
		fmt.Println("path:", e.Path)
		fmt.Println("type:", e.Type.String())
		fmt.Println("state:", e.State.String())*/
		cancelFunc()
		fmt.Printf("取消所有子协程")
		fmt.Println("---------------------------")
	}
}

// 监听每一个节点的addr数据变化
func (s *ServerRegister) watchNode(ctx context.Context, nodePath, node string) {

	for {
		select {
		case <-ctx.Done():
			fmt.Printf("退出当前协程: %s\n", nodePath)
			return
		default:
			// 建立新的grpc连接
			addrByte, _, err := s.conn.Get(nodePath)
			fmt.Println(addrByte)
			fmt.Println(string(addrByte))
			grpcclient.AddClient(node, string(addrByte))

			// 监听 node 的数据变化
			_, _, event, err := s.conn.GetW(nodePath)
			if err != nil {
				fmt.Println(err)
				return
			}

			<-event

			/*fmt.Println("发生 data change 回调：")
			fmt.Println("path:", e.Path)
			fmt.Println("type:", e.Type.String())
			fmt.Println("state:", e.State.String())*/

			grpcclient.RemoveClient(node)
			fmt.Println("data:", string(addrByte))

			fmt.Println("---------------------------")
		}
	}

}
